#include <sys/time.h>
#include <unistd.h>

#include <libubus.h>
#include <libubox/ustream.h>

static struct ubus_context *ctx;
static struct blob_buf b;
static int tx_count = 0;
static int rx_count = 0;

enum
{
    RETURN_CODE,
    RETURN_DATA,
    __RETURN_MAX,
};

static const struct blobmsg_policy return_policy[__RETURN_MAX] = {
    [RETURN_CODE] = {.name = "rc", .type = BLOBMSG_TYPE_INT32},
    [RETURN_DATA] = {.name = "data", .type = BLOBMSG_TYPE_STRING},
};

static void async_fd_data_cb(struct ustream *s, int bytes)
{
    char *data, *sep;
    int len;

    data = ustream_get_read_buf(s, &len);
    if (len < 1)
        return;

    sep = strchr(data, '\n');
    if (!sep)
        return;

    *sep = 0;
    fprintf(stderr, "Got line: %s\n", data);
    ustream_consume(s, sep + 1 - data);
}

static void async_fd_callback(struct ubus_request *req, int fd)
{
    static struct ustream_fd ufd;

    fprintf(stderr, "Got fd from the server, fd: %d\n", fd);

    ufd.stream.notify_read = async_fd_data_cb;
    ustream_fd_init(&ufd, fd);
}

static void async_complete_cb(struct ubus_request *req, int ret)
{
    fprintf(stderr, "completed request, ret: %d\n", ret);
}

static void async_request_service(void)
{
    static struct ubus_request req;
    uint32_t id;

    if (ubus_lookup_id(ctx, "device", &id))
    {
        fprintf(stderr, "Failed to look up 'device object\n");
        return;
    }

    /* read data from device */
    /* json:
     *    {
     *         "devicename": "device0",
     *         "fieldname": "version"
     *    }
     */
    blob_buf_init(&b, 0);
    blobmsg_add_string(&b, "devname", "device0");
    blobmsg_add_string(&b, "fieldname", "version");

    ubus_invoke_async(ctx, id, "read", b.head, &req);

    req.fd_cb = async_fd_callback;
    req.complete_cb = async_complete_cb;
    ubus_complete_request_async(ctx, &req);
}

int main(int argc, char **argv)
{
    const char *ubus_socket = NULL;

    uloop_init();

    ctx = ubus_connect(ubus_socket);
    if (!ctx)
    {
        fprintf(stderr, "Failed to connect to ubus\n");
        return -1;
    }

    ubus_add_uloop(ctx);

    async_request_service();

    uloop_run();
    ubus_free(ctx);
    uloop_done();

    return 0;
}
